// (1) next-auth에서 필요한 타입들을 import import NextAuth, { NextAuthOptions, // authOptions에 쓸 타입 Session, User } from 'next-auth' import { JWT } from "next-auth/jwt" import CredentialsProvider from 'next-auth/providers/credentials' import { verifyExternalCredentials, verifyOtp } from '@/lib/users/verifyOtp' // 1) 모듈 보강 선언 declare module "next-auth" { /** * Session 객체를 확장 */ interface Session { user: { /** 우리가 필요로 하는 user id */ id: string // 기본적으로 NextAuth가 제공하는 name/email/image 필드 name?: string | null email?: string | null image?: string | null companyId?: number | null domain?: string | null } } /** * User 객체를 확장 */ interface User { id: string imageUrl?: string | null companyId?: number | null domain?: string | null // 필요한 필드를 추가로 선언 가능 } } // (2) authOptions에 NextAuthOptions 타입 지정 export const authOptions: NextAuthOptions = { providers: [ CredentialsProvider({ name: 'Credentials', credentials: { email: { label: 'Email', type: 'text' }, code: { label: 'OTP code', type: 'text' }, }, async authorize(credentials, req) { const { email, code } = credentials ?? {} // OTP 검증 const user = await verifyOtp(email ?? '', code ?? '') if (!user) { return null } return { id: String(user.id ?? email ?? "dts"), email: user.email, imageUrl: user.imageUrl ?? null, name: user.name, // DB에서 가져온 실제 이름 companyId: user.companyId, // DB에서 가져온 실제 이름 domain: user.domain, // DB에서 가져온 실제 이름 } }, }), // 새로 추가할 ID/비밀번호 provider CredentialsProvider({ id: 'credentials-password', name: 'Username Password', credentials: { username: { label: "Username", type: "text" }, password: { label: "Password", type: "password" } }, async authorize(credentials, req) { // req 매개변수 추가 if (!credentials?.username || !credentials?.password) { return null; } try { // 여기서 외부 서비스 API를 호출하여 사용자 인증 const user = await verifyExternalCredentials( credentials.username, credentials.password ); if (user) { return { id: String(user.id), // id를 string으로 변환 name: user.name, email: user.email, // 첫 번째 provider와 동일한 필드 구조 유지 imageUrl: user.imageUrl ?? null, companyId: user.companyId, domain: user.domain }; } return null; } catch (error) { console.error("Authentication error:", error); return null; } } }) ], // (3) session.strategy는 'jwt'가 되도록 선언 // 필요하다면 as SessionStrategy 라고 명시해줄 수도 있음 // 예) strategy: 'jwt' as SessionStrategy session: { strategy: 'jwt', }, callbacks: { // (4) 콜백에서 token, user, session 등의 타입을 좀 더 명시해주고 싶다면 아래처럼 destructuring에 제네릭/타입 지정 async jwt({ token, user }: { token: JWT; user?: User }) { if (user) { token.id = user.id token.email = user.email token.name = user.name token.companyId = user.companyId token.domain = user.domain ; (token as any).imageUrl = (user as any).imageUrl } return token }, async session({ session, token }: { session: Session; token: JWT }) { if (token) { session.user = { id: token.id as string, email: token.email as string, name: token.name as string, domain: token.domain as string, companyId: token.companyId as number, image: (token as any).imageUrl ?? null } } return session }, }, } const handler = NextAuth(authOptions) export { handler as GET, handler as POST }